﻿using System;
using System.Data.Entity;
using System.Data.Objects;
using System.Data.Objects.DataClasses;
using System.Linq;
using System.Linq.Expressions;
using Marketplace.Engine.Utils;

namespace Marketplace.Engine.Repository.Generic
{
    /// <summary>
    /// Default implementation of IRepository
    /// </summary>
    /// <typeparam name="T">T is of type of Entity</typeparam>
    /// <typeparam name="TBase"></typeparam>
    public abstract class GenericRepository<T, TBase> : IRepository<T>, IDisposable
        where T : EntityObject
        where TBase : EntityObject
                                                                                 
    {
        private ObjectContext _context; 
        private readonly ObjectSet<TBase> _objectSet;

        protected GenericRepository(ObjectContext context)
        {
            _context = context;
            _objectSet = CreateObjectSet(context);
        }

        protected virtual ObjectSet<TBase> CreateObjectSet(ObjectContext context)
        {
            return context.CreateObjectSet<TBase>();
        }

        public ListResult<T> GetList(ListCondition<T> listCondition)
        {
            var listResult = new ListResult<T>();
            if (listCondition == null)
                return listResult;

            IQueryable<T> query = _objectSet.OfType<T>();
            if (listCondition.Filter != null)
                query = query.Where(listCondition.Filter);

            if (listCondition.IncludeProperties != null)
                query = listCondition.IncludeProperties.Split(new char[] {','}, StringSplitOptions.RemoveEmptyEntries).Aggregate(query, (current, includeProperty) => current.Include(includeProperty));

            if (listCondition.OrderBy != null)
                query = query.OrderBy(listCondition.OrderBy);
            else
            {
                if (listCondition.IsPagingEnabled)
                    query = query.OrderBy(GetEntityKeyName());
            }

            if (listCondition.IsPagingEnabled)
                query = query.Skip((int)(listCondition.PageNumber*listCondition.PageSize)).Take((int)listCondition.PageSize);

            listResult.Result = query.ToList();
            return listResult;
        }

        public T GetById(object id)
        {
            return null;
        }

        public T GetById(Expression<Func<T, bool>> filter)
        {
            IQueryable<T> query = _objectSet.OfType<T>();
            return query.Where(filter).FirstOrDefault();
        }

        public void Insert(T t)
        {
            var tb = t as TBase;
            if (tb == null)
                return;

            _objectSet.AddObject(tb);
            _context.SaveChanges();
        }

        public void Delete(T t)
        {
            var tb = t as TBase;
            if(tb == null)
                return;

            _objectSet.DeleteObject(tb);
            _context.SaveChanges();
        }

        public void Delete(object id)
        {
            throw new NotImplementedException();
        }

        public void Update(T t)
        {
            var tb = t as TBase;
            if (tb == null)
                return;

            _objectSet.Attach(tb);
            _context.SaveChanges();
        }

        public void BeginTransaction()
        {
            
        }

        public void Commit()
        {

        }

        public void Rollback()
        {

        }

        public void Dispose()
        {
            if (_context != null)
            {
                _context.Dispose();
                _context = null;
            }
        }

        private string GetEntityKeyName()
        {
            return _objectSet.EntitySet.ElementType.KeyMembers[0].ToString();
        }
    }
}